"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 极致RTO-硬件故障类
Case Name   : 开启极致RTO，业务压力后备机进行build过程中主机网卡停止3分钟
Create At   : 2020/1/5
Owner       : @peilinqian
Description :
    1、开启极致RTO
    2、备机进行重建
    3、主机网卡停止3分钟
    4、备机重建结果
    5、备机再次进行重建
    6、执行完成后，关闭极致RTO
Expect      :
    1、开启极致RTO成功
    2、备机开始进行重建
    3、主机网卡停止3分钟成功
    4、备机重建结果可能成功或者失败
    5、备机再次进行重建成功
    6、执行完成后，关闭极致RTO成功
History     :
    modified：2022-9-1 by 5328113;重建过程注入网卡停止3min故障，如果刚好在进行mot build，
    重建结果可能成功也可能失败，此处不进行断言，只要保证后续再次重建成功即可
    modified：2022-1-20 by 5328113; 注入网卡3min故障，build结果成功，优化用例逻辑
    modified：2021-9-3 by 5328113;cfe注入故障返回结果变更，优化断言；
    modified：2021-3-9 by 5328113;主备同步方法调用修改，增加超时等待时间；
    modified 2021-03-01 by @peilinqian；修改获取网卡逻辑
"""

import os
import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node


class ExtremeRto(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.log.info("----this is setup----")
        self.pri_root = Node(node='PrimaryRoot')
        self.pri_dbuser = Node(node='PrimaryDbUser')
        self.sta1_root = Node(node='Standby1Root')
        self.sta1_dbuser = Node(node='Standby1DbUser')
        self.sta2_dbuser = Node(node='Standby2DbUser')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.sta_1_sh = CommonSH('Standby1DbUser')
        self.sta_2_sh = CommonSH('Standby2DbUser')
        self.com = Common()
        self.constant = Constant()
        self.node_num = self.com.get_node_num(self.pri_root)
        self.log.info(self.node_num)
        self.max_time = 1200
        self.min_time = 300
        self.build_result = False

    def test_main(self):
        try:
            self.log.info('----1、开启极致RTO----')
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'replication_type=1')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_parse_workers=4')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_redo_workers=4')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'hot_standby=off')
            self.assertTrue(msg)
            # 重启数据库配置文件生效
            self.pri_sh.stopDbCluster()
            time.sleep(2)
            self.pri_sh.startDbCluster()

            self.log.info('----查看主机query，同步是否正常----')
            self.pri_sh.check_location_consistency('primary',
                                                   self.node_num,
                                                   self.min_time)
            self.log.info('----查询主备状态----')
            status = self.pri_sh.getDbClusterStatus('status')
            self.assertTrue(status)

            try:
                self.log.info('----2、备机进行重建----')
                success_msg = self.constant.REBUILD_SUCCESS_MSG
                build_thread = ComThread(self.sta_1_sh.executeGsctl,
                                         args=('build',
                                               success_msg,))
                build_thread.setDaemon(True)
                build_thread.start()
                time.sleep(5)

                self.log.info('----3、停止DN主机网卡3分钟----')
                self.log.info('----获取网卡----')
                network_cmd = 'ifconfig'
                self.log.info(network_cmd)
                network_result = self.pri_root.sh(network_cmd).result()
                network_list = network_result.split('\n\n')
                self.log.info(network_list)
                network = ''
                for network_item in network_list:
                    if self.pri_dbuser.db_host in network_item:
                        network = network_item.split(':')[0].strip()
                        self.log.info(network)

                self.log.info('----注入故障----')
                start_time = time.time()
                inject_cmd = f'rNet_down (dev, time)values({network}, 180)'
                self.log.info(inject_cmd)
                inject_result = self.com.cfe_inject(self.pri_root, inject_cmd)
                self.log.info(inject_result)
                self.assertIn(self.constant.cfe_inject_netdown_success_msg,
                              inject_result)

                self.step4_txt = '----4、备机重建结果；expect：成功或者失败----'
                self.log.info(self.step4_txt)
                # 等待build重建完成
                build_thread.join()
                self.build_result = build_thread.get_result()
                end_time = time.time()
                self.log.info("start_time:" + str(start_time) +
                              ";end_time:" + str(end_time))
                if end_time - start_time < 180:
                    time.sleep(180 - end_time + start_time)
            finally:
                if not self.build_result:
                    step5_txt = '----5、备机再次进行重建；expect：成功----'
                    self.log.info(step5_txt)
                    rebuild_result = self.sta_1_sh.build_fail_scp_crtfile()
                    if rebuild_result:
                        self.log.info('重建失败后，再次进行重建成功，已恢复')
                    else:
                        self.log.info('重建失败后，再次进行重建失败，请检查失败原因')
                    self.assertTrue(rebuild_result, '执行失败:' + step5_txt)
                else:
                    self.assertTrue(self.build_result,
                                    '执行失败:' + self.step4_txt)

            self.log.info('----增加同步是否正常----')
            self.pri_sh.check_location_consistency('primary',
                                                   self.node_num,
                                                   self.min_time)
            self.log.info('----查询主备状态----')
            status = self.pri_sh.getDbClusterStatus('status')
            self.assertTrue(status)

        finally:
            self.log.info('----6、执行完成后，关闭极致RTO----')
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_parse_workers = 1')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_redo_workers = 1')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'hot_standby=on')
            self.assertTrue(msg)
            # 重启数据库配置文件生效
            self.pri_sh.stopDbCluster()
            time.sleep(2)
            self.pri_sh.startDbCluster()

            # 校验备机是否完成数据同步
            self.log.info('校验备机是否完成数据同步')
            flag_1 = self.sta_1_sh.check_location_consistency('standby',
                                                              self.node_num,
                                                              self.min_time)
            self.assertTrue(flag_1)
            flag_2 = self.sta_2_sh.check_location_consistency('standby',
                                                              self.node_num,
                                                              self.min_time)
            self.assertTrue(flag_2)

            self.log.info('----查询主备状态----')
            status = self.pri_sh.getDbClusterStatus('status')
            self.assertTrue(status)

    def tearDown(self):
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
